package behaviour;
//rewrite to use the new maze

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import maze.Coordinate;
import maze.Direction;
import maze.Location;
import maze.Maze;

/**
 * Class to find pacman by efficiently exploring the map. All locations used
 * are sectorLocations (so (1,2) is the sector 1 sector north of the beginsector en 2 sectors east).
 * @author Niels en Maarten
 *
 */ 
public class PacmanFinder implements Strategy {
	private Coordinate currentCoordinate;
	private Maze maze;
	private Map<Coordinate,Integer> heuristic;
	public PacmanFinder (Location currentLocation, Maze maze){
		currentCoordinate=maze.getCoordinateOfLocation(currentLocation);
		this.maze=maze;
		heuristic= new HashMap<Coordinate,Integer>();
	}
	@Override
	public Direction nextDirection(){
		List<Coordinate> locationsVisited=maze.getUnexploredCoordinates();
		List<Direction> directions=maze.getClearDirections(currentCoordinate.getX(),currentCoordinate.getY(),true);
		Collections.shuffle(directions);
		//random direction is chosen
		Random random = new Random();
		Direction result= directions.get(random.nextInt(directions.size()-1));
		//if there is a direction that is not yet visited by the ghost, result is overwritten
//		result = getDirectionUnexploredLocation(directions, result);
		//if there is a direction with a better heuristic value than the other, result is overwritten
		Direction temporaryResult= getDirectionBestHeuristic(directions, result);
		if(temporaryResult!=null)
			result = temporaryResult;
		//if there is a direction that is not yet visited by the ghost nor by any other ghost, result is overwritten
		int numberOfOutcomes=0;
		for(Direction direction:directions){
			Coordinate nextLocation=Coordinate.getCoordinateInDirection(currentCoordinate, direction);
			if(!locationsVisited.contains(nextLocation)){
				result= direction;
				numberOfOutcomes++;
			}
		}
		if(numberOfOutcomes>1){
			heuristic.put(currentCoordinate, numberOfOutcomes+1);
			updateHeuristic(numberOfOutcomes, new ArrayList<Coordinate>(), currentCoordinate);
		}
		currentCoordinate=Coordinate.getCoordinateInDirection(currentCoordinate,result);
		return result;
		
	}
	/**
	 * Returns the direction (relative to currentLocation) in which the sector with the
	 * largest heuristic value is located.
	 * @param directions list of possible directions (not blocked by walls)
	 * @param result direction of the best heuristic sector
	 * @return result
	 */
	public Direction getDirectionBestHeuristic(List<Direction> directions,Direction result) {
		Direction firstDirection=directions.get(0);
		Coordinate firstCoordinate=Coordinate.getCoordinateInDirection(currentCoordinate, firstDirection);
		int maxHeuristic= heuristic.get(firstCoordinate);
		result=firstDirection;
		boolean notAllTheSame=false;
		for(Direction direction:directions){
			Coordinate nextCoordinate=Coordinate.getCoordinateInDirection(currentCoordinate, direction);
			int nextHeuristic = heuristic.get(nextCoordinate);
			if(nextHeuristic>maxHeuristic){
				result= direction;
				notAllTheSame=true;
			}
			if(nextHeuristic<maxHeuristic)
				notAllTheSame=true;
		}
		if(notAllTheSame==false){
			return result;
		}
		return null;
	}
	/**
	 * Returns the direction of the 
	 * @param directions
	 * @param result
	 * @return
	 */
//	public Direction getDirectionUnexploredLocation(
//			List<Direction> directions, Direction result) {
//		for(Direction direction:directions){
//			Coordinate nextCoordinate=Coordinate.getCoordinateInDirection(currentCoordinate, direction);
//			if(!locationsVisited.contains(nextCoordinate))
//				result= direction;
//		}
//		return result;
//	}


	private void updateHeuristic(int numberOfOutcomes, List<Coordinate> allreadyDone,Coordinate coordinate){
		if(numberOfOutcomes==0)
			return;
		int increment=numberOfOutcomes;
		List<Direction> directions=maze.getClearDirections(coordinate.getX(), coordinate.getY(), true);
		allreadyDone.add(coordinate);
		for(Direction direction: directions){
			Coordinate nextLocation=Coordinate.getCoordinateInDirection(currentCoordinate, direction);
			if(!allreadyDone.contains(nextLocation)){
				heuristic.put(nextLocation, heuristic.get(nextLocation)+increment);
				updateHeuristic(numberOfOutcomes-1, allreadyDone, nextLocation);
			}

		}
		
	}
	

}
